/*
 * OPIAM Suite
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */

package opiam.admin.faare.service.services.views.orgchart;

import com.lowagie.text.Document;
import com.lowagie.text.Graphic;
import com.lowagie.text.Image;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfWriter;

import org.apache.log4j.Logger;

import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;

import javax.swing.tree.DefaultMutableTreeNode;


/**
 * This class is used to generate a PDF orgchart form an OrgChartPanel
 *  generated orgchart.
 * The cells info (X,Y,w,h,attributes,photos) are conveyed in hastables for
 *  each node.
 *
 */
public final class PrintOrga
{
    /** Constructor private because this is a utility class. */
    private PrintOrga()
    {
    }

    /** Instance of logger. */
    private static Logger _logger = Logger.getLogger(OrgChartPanel.class);

    /** Orgchart width. */
    private static int maxporgaw = 0;

    /** Orgchart height. */
    private static int maxporgah = 0;

    /** Orgchart mode. */
    private static int direction = OrgChartPanel.HORIZONTAL;

    /** Factor to convert X coordinates to page size. */
    private static int fXSIZE = 0;

    /** Factor to convert Y coordinates to page size. */
    private static int fYSIZE = 0;

    /** Number of pages. */
    private static int nbPageY = 1;

//DW/2615/BeginPatch
    /** Default photo file name. */
    private static String defaultPhoto = null;
//DW/2615/EndPatch

    /** Some space. */
    private static final int SPACE1 = OrgChartPanel.SPACEV + OrgChartPanel.DX;

    /** Some space. */
    private static final int SPACE2 = 2 * OrgChartPanel.SPACEV;

    /** Some space. */
    private static final int SPACE3 = SPACE2 + OrgChartPanel.DX;

    /** Some space. */
    private static final int SPACE4 = SPACE1 + SPACE2;

    /** Font size. */
    private static final int FONT_SZ = 12;

    /** Conversion pixel=>PDF lib units. */
    private static final int F1 = 595;

    /** Conversion pixel=>PDF lib units. */
    private static final int F2 = 210;

    /** Line size. */
    private static final float LINE_SZ = 1.5f;

    /**
     * Updates orgchart size with current node.
     *
     * @param info  Node hashtable.
     */
    private static void computePageSize(final Hashtable info)
    {
        int x = 0;
        int y = 0;

        if ((info.get(OrgChartPanel.WIDTH) != null) &&
                (info.get(OrgChartPanel.XCOORD) != null))
        {
            x = ((Integer) info.get(OrgChartPanel.WIDTH)).intValue() +
                ((Integer) info.get(OrgChartPanel.XCOORD)).intValue();
        }

        if (maxporgaw < x)
        {
            maxporgaw = x;
        }

        if ((info.get(OrgChartPanel.HEIGHT) != null) &&
                (info.get(OrgChartPanel.YCOORD) != null))
        {
            y = ((Integer) info.get(OrgChartPanel.HEIGHT)).intValue() +
                ((Integer) info.get(OrgChartPanel.YCOORD)).intValue();
        }

        if (maxporgah < y)
        {
            maxporgah = y;
        }
    }

    /**
     * Computes orgchart size.
     *
     * @param node  Orgchart root node.
     */
    private static void computePageSize(final DefaultMutableTreeNode node)
    {
        Enumeration enum1 = node.children();

        while (enum1.hasMoreElements())
        {
            DefaultMutableTreeNode childnode = (DefaultMutableTreeNode) enum1.nextElement();
            Hashtable info = (Hashtable) childnode.getUserObject();
            computePageSize(info);
            computePageSize(childnode);
        }
    }

    /**
     * Draws rectangle and lines.
     *
     * @param g  PDF Graphic on which to draw.
     * @param node  Current node.
     * @param px  Page number on X coordinates.
     * @param py  Page number on Y coordinates.
     */
    private static void drawRectangle(final Graphic g,
        final DefaultMutableTreeNode node, final int px, final int py)
    {
        Hashtable info = (Hashtable) node.getUserObject();
        int x = ((Integer) info.get(OrgChartPanel.XCOORD)).intValue();
        int y = ((Integer) info.get(OrgChartPanel.YCOORD)).intValue();
        int w = ((Integer) info.get(OrgChartPanel.WIDTH)).intValue();
        int h = ((Integer) info.get(OrgChartPanel.HEIGHT)).intValue();

        int xd = (px - 1) * fXSIZE;
        int xf = px * fXSIZE;
        int yd = (nbPageY - py) * fYSIZE;

        g.rectangle(x - xd, maxporgah - y - h - OrgChartPanel.SPACEV - yd, w, h);

        int nbchild = node.getChildCount();

        if (nbchild > 0)
        {
            /* vertical line at bottom of node */
            if (direction == OrgChartPanel.HORIZONTAL)
            {
                g.moveTo((x + (w / 2)) - xd, maxporgah - y - h - OrgChartPanel.SPACEV - yd);
            }
            else
            {
                g.moveTo((x + w) - xd, maxporgah - y - (h / 2) - OrgChartPanel.SPACEV - yd);
            }

            Hashtable finfo = (Hashtable) ((DefaultMutableTreeNode) node.getFirstChild()).getUserObject();
            Hashtable linfo = (Hashtable) ((DefaultMutableTreeNode) node.getLastChild()).getUserObject();
            int fx = ((Integer) finfo.get(OrgChartPanel.XCOORD)).intValue();
            int lx = ((Integer) linfo.get(OrgChartPanel.XCOORD)).intValue();
            int fw = ((Integer) finfo.get(OrgChartPanel.WIDTH)).intValue();
            int lw = ((Integer) linfo.get(OrgChartPanel.WIDTH)).intValue();
            int fh = ((Integer) finfo.get(OrgChartPanel.HEIGHT)).intValue();
            int lh = ((Integer) linfo.get(OrgChartPanel.HEIGHT)).intValue();
            int fy = ((Integer) finfo.get(OrgChartPanel.YCOORD)).intValue();
            int ly = ((Integer) linfo.get(OrgChartPanel.YCOORD)).intValue();

            if (direction == OrgChartPanel.HORIZONTAL)
            {
                g.lineTo((x + (w / 2)) - xd, (maxporgah - fy + SPACE1) - yd);
            }
            else if (direction == OrgChartPanel.TREE)
            {
                g.moveTo(fx - SPACE3 - xd, maxporgah - y - h - OrgChartPanel.SPACEV - yd);
                g.lineTo(fx - SPACE3 - xd, maxporgah - fy - (fh / 2) - OrgChartPanel.SPACEV - yd);
            }
            else
            {
                g.lineTo(fx - SPACE3 - xd, maxporgah - y - (h / 2) - OrgChartPanel.SPACEV - yd);
            }

            /* horizontal line from first son to last son */
            int x0 = fx + (fw / 2);

            if (x0 < xd)
            {
                x0 = xd;
            }

            int x1 = lx + (lw / 2);

            if (x1 > xf)
            {
                x1 = xf;
            }

            if (direction == OrgChartPanel.HORIZONTAL)
            {
                g.moveTo(x0 - xd, (maxporgah - fy + SPACE1) - yd);
                g.lineTo(x1 - xd, (maxporgah - fy + SPACE1) - yd);
            }
            else
            {
                g.moveTo(fx - SPACE3 - xd, maxporgah - fy - (fh / 2) - OrgChartPanel.SPACEV - yd);
                g.lineTo(fx - SPACE3 - xd, maxporgah - ly - (lh / 2) - OrgChartPanel.SPACEV - yd);
            }

            /* vertical lines at top of sons */
            Enumeration enum1 = node.children();

            while (enum1.hasMoreElements())
            {
                DefaultMutableTreeNode childnode = (DefaultMutableTreeNode) enum1.nextElement();
                Hashtable cinfo = (Hashtable) childnode.getUserObject();
                int cx = ((Integer) cinfo.get(OrgChartPanel.XCOORD)).intValue();
                int cw = ((Integer) cinfo.get(OrgChartPanel.WIDTH)).intValue();
                int cy = ((Integer) cinfo.get(OrgChartPanel.YCOORD)).intValue();
                int ch = ((Integer) cinfo.get(OrgChartPanel.HEIGHT)).intValue();

                if (direction == OrgChartPanel.HORIZONTAL)
                {
                    g.moveTo((cx + (fw / 2)) - xd, (maxporgah - fy + SPACE1) - yd);
                    g.lineTo((cx + (lw / 2)) - xd, maxporgah - fy - OrgChartPanel.SPACEV - yd);
                }
                else
                {
                    g.moveTo(fx - SPACE3 - xd, maxporgah - cy - (ch / 2) - OrgChartPanel.SPACEV - yd);
                    g.lineTo(fx - xd, maxporgah - cy - (ch / 2) - OrgChartPanel.SPACEV - yd);
                }
            }
        }

        Enumeration enum1 = node.children();

        while (enum1.hasMoreElements())
        {
            DefaultMutableTreeNode childnode = (DefaultMutableTreeNode) enum1.nextElement();
            drawRectangle(g, childnode, px, py);
        }
    }

    //DW/2573/BeginPatch

    /**
     * Draws rectangle and lines, in Sema mode.
     *
     * @param g  PDF Graphic on which to draw.
     * @param node  Current node.
     * @param px  Page number on X coordinates.
     * @param py  Page number on Y coordinates.
     */
    private static void drawRectangleSema(final Graphic g,
        final DefaultMutableTreeNode node, final int px, final int py)
    {
        Hashtable info = (Hashtable) node.getUserObject();
        int x = ((Integer) info.get(OrgChartPanel.XCOORD)).intValue();
        int y = ((Integer) info.get(OrgChartPanel.YCOORD)).intValue();
        int w = ((Integer) info.get(OrgChartPanel.WIDTH)).intValue();
        int h = ((Integer) info.get(OrgChartPanel.HEIGHT)).intValue();

        int xd = (px - 1) * fXSIZE;
        int xf = px * fXSIZE;
        int yd = (nbPageY - py) * fYSIZE;

        g.rectangle(x - xd, maxporgah - y - h - OrgChartPanel.SPACEV - yd, w, h);

        int nbchild = node.getChildCount();

        if (nbchild > 0)
        {
            /* vertical line at bottom of node */
            g.moveTo((x + (w / 2)) - xd, maxporgah - y - h - OrgChartPanel.SPACEV - yd);

            Hashtable finfo = (Hashtable) ((DefaultMutableTreeNode) node.getFirstChild()).getUserObject();
            Hashtable linfo = (Hashtable) ((DefaultMutableTreeNode) node.getLastChild()).getUserObject();
            int fx = ((Integer) finfo.get(OrgChartPanel.XCOORD)).intValue();
            int lx = ((Integer) linfo.get(OrgChartPanel.XCOORD)).intValue();
            int fw = ((Integer) finfo.get(OrgChartPanel.WIDTH)).intValue();
            int lw = ((Integer) linfo.get(OrgChartPanel.WIDTH)).intValue();
            int fh = ((Integer) finfo.get(OrgChartPanel.HEIGHT)).intValue();
            int lh = ((Integer) linfo.get(OrgChartPanel.HEIGHT)).intValue();
            int fy = ((Integer) finfo.get(OrgChartPanel.YCOORD)).intValue();
            int ly = ((Integer) linfo.get(OrgChartPanel.YCOORD)).intValue();

            g.lineTo((x + (w / 2)) - xd, (maxporgah - ly + OrgChartPanel.DX) - yd);

            /* rectangles and vertical lines at top of sons */
            Enumeration enum1 = node.children();

            int prevx = -1;
            int prevy = -1;

            while (enum1.hasMoreElements())
            {
                DefaultMutableTreeNode childnode = (DefaultMutableTreeNode) enum1.nextElement();
                Hashtable cinfo = (Hashtable) childnode.getUserObject();
                int cx = ((Integer) cinfo.get(OrgChartPanel.XCOORD)).intValue();
                int cw = ((Integer) cinfo.get(OrgChartPanel.WIDTH)).intValue();
                int cy = ((Integer) cinfo.get(OrgChartPanel.YCOORD)).intValue();
                int ch = ((Integer) cinfo.get(OrgChartPanel.HEIGHT)).intValue();

                g.rectangle(cx - xd, maxporgah - cy - h - OrgChartPanel.SPACEV - yd, cw, ch);

                g.moveTo((cx + (fw / 2)) - xd, (maxporgah - cy + OrgChartPanel.DX) - yd);
                g.lineTo((cx + (lw / 2)) - xd, maxporgah - cy - OrgChartPanel.SPACEV - yd);

                if (cy == prevy)
                {
                    g.moveTo((prevx + (fw / 2)) - xd, (maxporgah - cy + OrgChartPanel.DX) -
                        yd);
                    g.lineTo((cx + (fw / 2)) - xd, (maxporgah - cy + OrgChartPanel.DX) - yd);
                }

                prevx = cx;
                prevy = cy;
            }
        }
    }

    //DW/2573/EndPatch

    /**
     * Draws text in cells.
     *
     * @param cb  PDF content on which to draw.
     * @param node  Current node.
     * @param attribs  Attributes of node to insert.
     * @param defsize  Font default size.
     * @param px  Page number on X coordinates.
     * @param py  Page number on Y coordinates.
     */
    private static void drawText(final PdfContentByte cb,
        final DefaultMutableTreeNode node, final List attribs,
        final int defsize, final int px, final int py)
    {
        Hashtable info = (Hashtable) node.getUserObject();
        int x = ((Integer) info.get(OrgChartPanel.XCOORD)).intValue();
        int y = ((Integer) info.get(OrgChartPanel.YCOORD)).intValue();

        int ipx = x;
        int xd = (px - 1) * fXSIZE;
        int xf = px * fXSIZE;
        int yd = (nbPageY - py) * fYSIZE;

        x = x - xd;
        y = y + yd;

        Iterator iter = attribs.iterator();
        List alist = (List) info.get(OrgChartPanel.ATTRIBS);

        if (alist != null)
        {
            iter = alist.iterator();
        }

        int line = 1;

        int dx;

        if (info.get(OrgChartPanel.PHOTO) != null)
        {
            dx = OrgChartPanel.DX_PHOTO;
        }
        else
        {
            dx = OrgChartPanel.SPACEV;
        }

        cb.setTextMatrix(x + dx, maxporgah - y - SPACE4);

        BaseFont bf = null;

        try
        {
            bf = BaseFont.createFont("Helvetica", "Cp1252", false);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        int newsize = defsize;
        int linesSpace = 0;

        while (iter.hasNext())
        {
            String attyp = (String) iter.next();

            if (!attyp.equals(OrgChartPanel.PHOTO))
            {
                String atVal = null;

                if (attyp.equals("displayname"))
                {
                    atVal = (String) info.get(OrgChartPanel.NAME);
                }
                else
                {
                    atVal = (String) info.get(attyp);
                }

                if (atVal != null)
                {
                    newsize = defsize;

                    float space = ((Integer) info.get(OrgChartPanel.WIDTH)).intValue() -
                        bf.getWidthPoint(atVal, newsize) - dx;

                    while (space < 0)
                    {
                        newsize--;
                        cb.setFontAndSize(bf, newsize);
                        space = ((Integer) info.get(OrgChartPanel.WIDTH)).intValue() -
                            bf.getWidthPoint(atVal, newsize) - dx;
                    }

                    float availspace = ((Integer) info.get(OrgChartPanel.WIDTH)).intValue() -
                        bf.getWidthPoint(atVal, newsize) - dx;
                    float coef = 1.1f;
                    cb.setTextMatrix(x + dx + (availspace / 2),
                        maxporgah - y - OrgChartPanel.SPACEV - ((int) (newsize * coef)) -
                        linesSpace);
                    linesSpace += (int) (newsize * coef);
                    line++;
                    cb.showText(atVal);
                }
            }
        }

        if (newsize != defsize)
        {
            cb.setFontAndSize(bf, defsize);
        }

        Enumeration enum1 = node.children();

        while (enum1.hasMoreElements())
        {
            DefaultMutableTreeNode childnode = (DefaultMutableTreeNode) enum1.nextElement();
            drawText(cb, childnode, attribs, defsize, px, py);
        }
    }

    /**
     * Draws photos in cells.
     *
     * @param cb  PDF Content on which to draw.
     * @param node  Current node.
     * @param px  Page number on X coordinates.
     * @param py  Page number on Y coordinates.
     *
     * @throws Exception  In case the photo is not in a recognized format.
     */
    private static void drawImage(final PdfContentByte cb,
        final DefaultMutableTreeNode node, final int px, final int py)
        throws Exception
    {
        Hashtable info = (Hashtable) node.getUserObject();
        int x = ((Integer) info.get(OrgChartPanel.XCOORD)).intValue();
        int y = ((Integer) info.get(OrgChartPanel.YCOORD)).intValue();

        int ipx = x;
        int xd = (px - 1) * fXSIZE;
        int xf = px * fXSIZE;

        int yd = (nbPageY - py) * fYSIZE;

        if ((xd <= ipx) && (ipx <= xf))
        {
            x = x - xd;
            y = y + yd;

            byte[] photo = (byte[]) info.get(OrgChartPanel.PHOTO);

//DW/2615/BeginPatch
            Image img1 = null;


            if (photo != null)
            {
                img1 = Image.getInstance(photo);
            }
//DW/2643/BeginPatch
            else if (defaultPhoto != null)
//DW/2643/EndPatch
            {
                img1 = Image.getInstance(defaultPhoto);
            }

            if (img1 != null)
            {
//DW/2615/EndPatch
                float coef1 = (float) 100.0;
                float coef2 = (float) 100.0;
                int h = ((Integer) info.get(OrgChartPanel.HEIGHT)).intValue() -
                    SPACE1;

                if (img1.top() > h)
                {
                    coef1 = (int) ((h * 100) / img1.top());
                }

                if (img1.right() > OrgChartPanel.PHOTO_SZ)
                {
                    coef2 = (int) (OrgChartPanel.PHOTO_SZ * 100 / img1.right());
                }

                float coef = ((coef1 < coef2) ? coef1 : coef2);
                img1.setAbsolutePosition(x + OrgChartPanel.DX,
                    maxporgah - y - SPACE1 - ((img1.top() * coef) / 100));
                img1.scalePercent(coef, coef);

                try
                {
                    cb.addImage(img1);
                }
                catch (Exception e)
                {
                    System.out.println(e.getMessage());
                }
            }
        }

        // end test ipx
        Enumeration enum1 = node.children();

        while (enum1.hasMoreElements())
        {
            DefaultMutableTreeNode childnode = (DefaultMutableTreeNode) enum1.nextElement();
            drawImage(cb, childnode, px, py);
        }
    }

    /**
     * Generates PDF orgchart on file.
     *
     * @param filename  Output file name.
     * @param tree  Orgchart nodes.
     * @param attribs  Cells attributes.
     * @param xpage  Page size on X coordinates.
     * @param ypage  Page size on Y coordinates.
     */
    public static void doPrintOrga(final String filename,
        final DefaultMutableTreeNode tree, final List attribs, final int xpage,
        final int ypage)
    {
        // NOTE ! assume all x,y,w,h are set
        fXSIZE = (xpage * F1) / F2;
        fYSIZE = (ypage * F1) / F2;

        maxporgaw = 0;
        maxporgah = 0;
        computePageSize((Hashtable) tree.getUserObject());
        computePageSize(tree);
        maxporgah += SPACE2;
        maxporgaw += SPACE2;

        Hashtable info = (Hashtable) tree.getUserObject();

        direction = OrgChartPanel.HORIZONTAL;

        if (tree.getChildCount() == 1)
        {
            DefaultMutableTreeNode child = (DefaultMutableTreeNode) tree.getFirstChild();
            Hashtable cinfo = (Hashtable) child.getUserObject();
            int xc = ((Integer) cinfo.get(OrgChartPanel.XCOORD)).intValue();
            int yc = ((Integer) cinfo.get(OrgChartPanel.YCOORD)).intValue();
            int xt = ((Integer) info.get(OrgChartPanel.XCOORD)).intValue();
            int yt = ((Integer) info.get(OrgChartPanel.YCOORD)).intValue();

            if (yc == yt)
            {
                direction = OrgChartPanel.VERTICAL;
            }
            else if (xc != xt)
            {
                direction = OrgChartPanel.TREE;
            }
        }
        else if (tree.getChildCount() != 0)
        {
            int x1 = ((Integer) ((Hashtable) ((DefaultMutableTreeNode) tree.getFirstChild()).getUserObject())
                            .get(OrgChartPanel.XCOORD)).intValue();
            int x2 = ((Integer) ((Hashtable) ((DefaultMutableTreeNode) tree.getLastChild()).getUserObject())
                            .get(OrgChartPanel.XCOORD)).intValue();

            if (x1 == x2)
            {
                int y = ((Integer) info.get(OrgChartPanel.YCOORD)).intValue();
                int y1 = ((Integer) ((Hashtable) ((DefaultMutableTreeNode) tree.getFirstChild())
                            .getUserObject()).get(OrgChartPanel.YCOORD)).intValue();

                if (y1 < y)
                {
                    direction = OrgChartPanel.VERTICAL;
                }
                else
                {
                    direction = OrgChartPanel.TREE;
                }
            }
        }

        if (fXSIZE == 0)
        {
            fXSIZE = maxporgaw;
        }
        else
        {
            int cwidth = ((Integer) (info.get(OrgChartPanel.WIDTH))).intValue() +
                OrgChartPanel.SPACEV;

            if (direction == OrgChartPanel.VERTICAL)
            {
                cwidth += OrgChartPanel.PHOTO_SZ;
            }

            int nbcaz = fXSIZE / cwidth;
            fXSIZE = nbcaz * cwidth;
        }

        if (fYSIZE == 0)
        {
            fYSIZE = maxporgah;
        }

        int nbPageX = ((maxporgaw - SPACE2) / fXSIZE) + 1;
        nbPageY = ((maxporgah - SPACE2) / fYSIZE) + 1;

        maxporgah = nbPageY * fYSIZE;

        Document document = new Document(new Rectangle(fXSIZE, fYSIZE), OrgChartPanel.SPACEV, OrgChartPanel.SPACEV,
                OrgChartPanel.SPACEV, OrgChartPanel.SPACEV);

        try
        {
            PdfWriter writer = PdfWriter.getInstance(document,
                    new FileOutputStream(filename));
            document.open();

            PdfContentByte cb = writer.getDirectContent();

            for (int x = 1; x <= nbPageX; x++)
            {
                for (int y = 1; y <= nbPageY; y++)
                {
                    if ((x > 1) || (y > 1))
                    {
                        document.newPage();
                    }

                    Graphic grx = new Graphic();
                    grx.setLineWidth(LINE_SZ);

                    // 1 - draw rectangles
                    drawRectangle(grx, tree, x, y);
                    grx.stroke();
                    document.add(grx);

                    // 2 - add attributes
                    cb.beginText();

                    BaseFont bf = BaseFont.createFont("Helvetica", "Cp1252",
                            false);
                    int size = FONT_SZ;
                    java.awt.Font f;

                    /*if ((f = sch.getTextFont()) != null)
                    {
                       size = f.getSize();
                    }*/
                    cb.setFontAndSize(bf, size);
                    drawText(cb, tree, attribs, size, x, y);

                    cb.endText();

                    // 3 - add images
                    drawImage(cb, tree, x, y);
                }

                // end y
            }

            // end x
        }
        catch (Exception e)
        {
            System.err.println(e.getMessage());
        }

        document.close();
    }

    /**
     * Generates PDF orgchart on stream.
     *
     * @param tree  Orgchart nodes.
     * @param attribs  Cells attributes.
     * @param xpage  Page size on X coordinates.
     * @param ypage  Page size on Y coordinates.
     *
     * @return PDF orgchart stream.
     */
    public static ByteArrayOutputStream doPrintOrga(
        final DefaultMutableTreeNode tree, final List attribs, final int xpage,
        final int ypage)
    {
        // NOTE ! assume all x,y,w,h are set
        fXSIZE = (xpage * F1) / F2;
        fYSIZE = (ypage * F1) / F2;

        maxporgaw = 0;
        maxporgah = 0;
        computePageSize((Hashtable) tree.getUserObject());
        computePageSize(tree);
        maxporgah += SPACE2;
        maxporgaw += SPACE2;

        Hashtable info = (Hashtable) tree.getUserObject();

        direction = OrgChartPanel.HORIZONTAL;

        if (tree.getChildCount() == 1)
        {
            DefaultMutableTreeNode child = (DefaultMutableTreeNode) tree.getFirstChild();
            Hashtable cinfo = (Hashtable) child.getUserObject();
            int xc = ((Integer) cinfo.get(OrgChartPanel.XCOORD)).intValue();
            int yc = ((Integer) cinfo.get(OrgChartPanel.YCOORD)).intValue();
            int xt = ((Integer) info.get(OrgChartPanel.XCOORD)).intValue();
            int yt = ((Integer) info.get(OrgChartPanel.YCOORD)).intValue();

            if (yc == yt)
            {
                direction = OrgChartPanel.VERTICAL;
            }
            else if (xc != xt)
            {
                direction = OrgChartPanel.TREE;
            }
        }
        else if (tree.getChildCount() != 0)
        {
            int x1 = ((Integer) ((Hashtable) ((DefaultMutableTreeNode) tree.getFirstChild())
                                  .getUserObject()).get(OrgChartPanel.XCOORD)).intValue();
            int x2 = ((Integer) ((Hashtable) ((DefaultMutableTreeNode) tree.getLastChild())
                                  .getUserObject()).get(OrgChartPanel.XCOORD)).intValue();

            if (x1 == x2)
            {
                int y = ((Integer) info.get(OrgChartPanel.YCOORD)).intValue();
                int y1 = ((Integer) ((Hashtable) ((DefaultMutableTreeNode) tree.getFirstChild())
                                  .getUserObject()).get(OrgChartPanel.YCOORD)).intValue();

                if (y1 < y)
                {
                    direction = OrgChartPanel.VERTICAL;
                }
                else
                {
                    direction = OrgChartPanel.TREE;
                }
            }

            //DW/2573/Beginpatch
            else
            {
                int h = ((Integer) info.get(OrgChartPanel.HEIGHT)).intValue();
                int y = ((Integer) info.get(OrgChartPanel.YCOORD)).intValue();
                int y1 = ((Integer) ((Hashtable) ((DefaultMutableTreeNode) tree.getFirstChild())
                                             .getUserObject()).get(OrgChartPanel.YCOORD)).intValue();
                int y2 = ((Integer) ((Hashtable) ((DefaultMutableTreeNode) tree.getLastChild())
                                             .getUserObject()).get(OrgChartPanel.YCOORD)).intValue();

                if (y1 != y2)
                {
                    direction = OrgChartPanel.SEMALIKE;
                }

                if (y1 < (y + h + SPACE3))
                {
                    direction = OrgChartPanel.SEMALIKE;
                }
            }

            //DW/2573/EndPatch
        }

        _logger.debug("direction  : " + direction);

        if (fXSIZE == 0)
        {
            fXSIZE = maxporgaw;
        }
        else
        {
            int cwidth = ((Integer) (info.get(OrgChartPanel.WIDTH))).intValue() +
                OrgChartPanel.SPACEV;

            if (direction == OrgChartPanel.VERTICAL)
            {
                cwidth += OrgChartPanel.PHOTO_SZ;
            }

            int nbcaz = fXSIZE / cwidth;
            fXSIZE = nbcaz * cwidth;
        }

        if (fYSIZE == 0)
        {
            fYSIZE = maxporgah;
        }

        int nbPageX = ((maxporgaw - SPACE2) / fXSIZE) + 1;
        nbPageY = ((maxporgah - SPACE2) / fYSIZE) + 1;

        maxporgah = nbPageY * fYSIZE;

        Document document = new Document(new Rectangle(fXSIZE, fYSIZE), OrgChartPanel.SPACEV, OrgChartPanel.SPACEV,
                OrgChartPanel.SPACEV, OrgChartPanel.SPACEV);

        ByteArrayOutputStream buf = new ByteArrayOutputStream();

        try
        {
            //BufferedOutputStream buf = new BufferedOutputStream( new OutputStream());

            /*PdfWriter writer =
                PdfWriter.getInstance(document, new FileOutputStream(filename));*/
            PdfWriter writer = PdfWriter.getInstance(document, buf);
            document.open();

            PdfContentByte cb = writer.getDirectContent();

            for (int x = 1; x <= nbPageX; x++)
            {
                for (int y = 1; y <= nbPageY; y++)
                {
                    if ((x > 1) || (y > 1))
                    {
                        document.newPage();
                    }

                    Graphic grx = new Graphic();
                    grx.setLineWidth(LINE_SZ);

                    // 1 - draw rectangles
                    //DW/2573/BeginPatch
                    if (direction == OrgChartPanel.SEMALIKE)
                    {
                        drawRectangleSema(grx, tree, x, y);
                    }
                    else
                    {
                        drawRectangle(grx, tree, x, y);
                    }

                    //DW/2573/EndPatch
                    grx.stroke();
                    document.add(grx);

                    // 2 - add attributes
                    cb.beginText();

                    BaseFont bf = BaseFont.createFont("Helvetica", "Cp1252",
                            false);
                    int size = FONT_SZ;
                    java.awt.Font f;

                    /*if ((f = sch.getTextFont()) != null)
                    {
                       size = f.getSize();
                    }*/
                    cb.setFontAndSize(bf, size);
                    drawText(cb, tree, attribs, size, x, y);

                    cb.endText();

                    // 3 - add images
                    drawImage(cb, tree, x, y);
                }

                // end y
            }

            // end x
        }
        catch (Exception e)
        {
            System.err.println(e.getMessage());
        }

        document.close();

        return buf;
    }

//DW/2615/BeginPatch
    /**
     * Sets default photo file name.
     *
     * @param value  File name.
     */
    public static void setDefaultPhoto(String value)
    {
        defaultPhoto = value;
    }
//DW/2615/EndPatch
}
